Skip to content

Fix wfctl falsely reporting older GitHub release as a newer version#328

Merged
intel352 merged 3 commits intomainfrom
copilot/fix-wfctl-version-check
Mar 14, 2026
Merged

Fix wfctl falsely reporting older GitHub release as a newer version#328
intel352 merged 3 commits intomainfrom
copilot/fix-wfctl-version-check

Conversation

Copy link
Contributor

Copilot AI commented Mar 14, 2026

checkForUpdateNotice and runUpdate compared versions with string inequality (latest != current), causing a newer locally-installed version to be told an older GitHub release is "available".

Changes

  • isNewerVersion(latestVer, currentVer string) bool — new helper using golang.org/x/mod/semver (already a transitive dep) for strict semver ordering; handles optional v prefix and invalid inputs
  • checkForUpdateNotice — replace latest != current with isNewerVersion(latest, current) so the notice only fires when the release is genuinely newer
  • runUpdate — both the --check reporting path and the install path now use isNewerVersion, so running a pre-release or ahead-of-latest build no longer triggers a spurious downgrade prompt
# Before
wfctl version  # running v0.3.42
⚡ wfctl v0.3.41 is available (you have v0.3.42). Run 'wfctl update' to upgrade.

# After: no notice printed when current ≥ latest

📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix wfctl version check for older versions Fix wfctl falsely reporting older GitHub release as a newer version Mar 14, 2026
Copilot AI requested a review from intel352 March 14, 2026 04:08
@intel352 intel352 marked this pull request as ready for review March 14, 2026 13:40
Copilot AI review requested due to automatic review settings March 14, 2026 13:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes wfctl update checks that incorrectly reported an older GitHub release as “available” when the locally installed version is newer, by comparing versions using semantic version ordering.

Changes:

  • Add isNewerVersion(latestVer, currentVer string) bool using golang.org/x/mod/semver for strict semver comparison.
  • Update checkForUpdateNotice and runUpdate to use isNewerVersion instead of string inequality.
  • Add regression/unit tests covering the “older release suppressed” scenarios and semver comparison behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
cmd/wfctl/update.go Switch update/notice logic to semver-based “latest > current” comparisons via a new helper.
cmd/wfctl/update_test.go Add unit/regression tests for isNewerVersion, notice suppression, and runUpdate behavior when current is newer.

Comment on lines +332 to +341
r, w, _ := os.Pipe()
os.Stderr = w

done := checkForUpdateNotice()
<-done

w.Close()
var buf [512]byte
n, _ := r.Read(buf[:])
os.Stderr = origStderr
@github-actions
Copy link

github-actions bot commented Mar 14, 2026

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:244: parsing iteration count: invalid syntax
baseline-bench.txt:312281: parsing iteration count: invalid syntax
baseline-bench.txt:595245: parsing iteration count: invalid syntax
baseline-bench.txt:887473: parsing iteration count: invalid syntax
baseline-bench.txt:1177553: parsing iteration count: invalid syntax
baseline-bench.txt:1484898: parsing iteration count: invalid syntax
benchmark-results.txt:244: parsing iteration count: invalid syntax
benchmark-results.txt:312920: parsing iteration count: invalid syntax
benchmark-results.txt:621705: parsing iteration count: invalid syntax
benchmark-results.txt:933070: parsing iteration count: invalid syntax
benchmark-results.txt:1249742: parsing iteration count: invalid syntax
benchmark-results.txt:1550280: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                  7.398m ± 59%
ComponentLoad-4                        3.424m ±  1%
ComponentExecute-4                     2.000µ ±  1%
PoolContention/workers-1-4             1.087µ ±  1%
PoolContention/workers-2-4             1.080µ ±  4%
PoolContention/workers-4-4             1.085µ ±  1%
PoolContention/workers-8-4             1.091µ ±  3%
PoolContention/workers-16-4            1.087µ ±  2%
ComponentLifecycle-4                   3.458m ±  1%
SourceValidation-4                     2.271µ ±  1%
RegistryConcurrent-4                   751.9n ±  1%
LoaderLoadFromString-4                 3.492m ±  1%
geomean                                18.47µ

                            │ benchmark-results.txt │
                            │         B/op          │
InterpreterCreation-4                  1.944Mi ± 0%
ComponentLoad-4                        2.097Mi ± 0%
ComponentExecute-4                     1.203Ki ± 0%
PoolContention/workers-1-4             1.203Ki ± 0%
PoolContention/workers-2-4             1.203Ki ± 0%
PoolContention/workers-4-4             1.203Ki ± 0%
PoolContention/workers-8-4             1.203Ki ± 0%
PoolContention/workers-16-4            1.203Ki ± 0%
ComponentLifecycle-4                   2.099Mi ± 0%
SourceValidation-4                     1.984Ki ± 0%
RegistryConcurrent-4                   1.133Ki ± 0%
LoaderLoadFromString-4                 2.099Mi ± 0%
geomean                                15.05Ki

                            │ benchmark-results.txt │
                            │       allocs/op       │
InterpreterCreation-4                   15.09k ± 0%
ComponentLoad-4                         17.43k ± 0%
ComponentExecute-4                       25.00 ± 0%
PoolContention/workers-1-4               25.00 ± 0%
PoolContention/workers-2-4               25.00 ± 0%
PoolContention/workers-4-4               25.00 ± 0%
PoolContention/workers-8-4               25.00 ± 0%
PoolContention/workers-16-4              25.00 ± 0%
ComponentLifecycle-4                    17.48k ± 0%
SourceValidation-4                       32.00 ± 0%
RegistryConcurrent-4                     2.000 ± 0%
LoaderLoadFromString-4                  17.47k ± 0%
geomean                                  181.2

cpu: AMD EPYC 9V74 80-Core Processor                
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4               6.806m ± 55%
ComponentLoad-4                     3.392m ±  0%
ComponentExecute-4                  1.908µ ±  2%
PoolContention/workers-1-4          1.039µ ±  1%
PoolContention/workers-2-4          1.032µ ±  2%
PoolContention/workers-4-4          1.041µ ±  0%
PoolContention/workers-8-4          1.047µ ±  2%
PoolContention/workers-16-4         1.044µ ±  1%
ComponentLifecycle-4                3.427m ±  1%
SourceValidation-4                  2.069µ ±  1%
RegistryConcurrent-4                762.9n ±  6%
LoaderLoadFromString-4              3.478m ±  1%
geomean                             17.80µ

                            │ baseline-bench.txt │
                            │        B/op        │
InterpreterCreation-4               1.944Mi ± 0%
ComponentLoad-4                     2.097Mi ± 0%
ComponentExecute-4                  1.203Ki ± 0%
PoolContention/workers-1-4          1.203Ki ± 0%
PoolContention/workers-2-4          1.203Ki ± 0%
PoolContention/workers-4-4          1.203Ki ± 0%
PoolContention/workers-8-4          1.203Ki ± 0%
PoolContention/workers-16-4         1.203Ki ± 0%
ComponentLifecycle-4                2.099Mi ± 0%
SourceValidation-4                  1.984Ki ± 0%
RegistryConcurrent-4                1.133Ki ± 0%
LoaderLoadFromString-4              2.099Mi ± 0%
geomean                             15.05Ki

                            │ baseline-bench.txt │
                            │     allocs/op      │
InterpreterCreation-4                15.09k ± 0%
ComponentLoad-4                      17.43k ± 0%
ComponentExecute-4                    25.00 ± 0%
PoolContention/workers-1-4            25.00 ± 0%
PoolContention/workers-2-4            25.00 ± 0%
PoolContention/workers-4-4            25.00 ± 0%
PoolContention/workers-8-4            25.00 ± 0%
PoolContention/workers-16-4           25.00 ± 0%
ComponentLifecycle-4                 17.48k ± 0%
SourceValidation-4                    32.00 ± 0%
RegistryConcurrent-4                  2.000 ± 0%
LoaderLoadFromString-4               17.47k ± 0%
geomean                               181.2

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                    287.7n ± 10%
CircuitBreakerExecution_Success-4            22.51n ±  0%
CircuitBreakerExecution_Failure-4            65.44n ±  0%
geomean                                      75.11n

                                  │ benchmark-results.txt │
                                  │         B/op          │
CircuitBreakerDetection-4                    144.0 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

                                  │ benchmark-results.txt │
                                  │       allocs/op       │
CircuitBreakerDetection-4                    1.000 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

cpu: AMD EPYC 9V74 80-Core Processor                
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  296.6n ± 7%
CircuitBreakerExecution_Success-4          22.67n ± 0%
CircuitBreakerExecution_Failure-4          70.33n ± 0%
geomean                                    77.90n

                                  │ baseline-bench.txt │
                                  │        B/op        │
CircuitBreakerDetection-4                 144.0 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │
                                  │     allocs/op      │
CircuitBreakerDetection-4                 1.000 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        934.8n ± 15%
JQTransform_ObjectConstruction-4            1.438µ ±  0%
JQTransform_ArraySelect-4                   3.290µ ±  0%
JQTransform_Complex-4                       37.70µ ±  2%
JQTransform_Throughput-4                    1.765µ ±  0%
SSEPublishDelivery-4                        65.94n ±  0%
geomean                                     1.639µ

                                 │ benchmark-results.txt │
                                 │         B/op          │
JQTransform_Simple-4                      1.273Ki ± 0%
JQTransform_ObjectConstruction-4          1.773Ki ± 0%
JQTransform_ArraySelect-4                 2.625Ki ± 0%
JQTransform_Complex-4                     16.22Ki ± 0%
JQTransform_Throughput-4                  1.984Ki ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                 │ benchmark-results.txt │
                                 │       allocs/op       │
JQTransform_Simple-4                        10.00 ± 0%
JQTransform_ObjectConstruction-4            15.00 ± 0%
JQTransform_ArraySelect-4                   30.00 ± 0%
JQTransform_Complex-4                       324.0 ± 0%
JQTransform_Throughput-4                    17.00 ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

cpu: AMD EPYC 9V74 80-Core Processor                
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     832.4n ± 30%
JQTransform_ObjectConstruction-4         1.386µ ±  1%
JQTransform_ArraySelect-4                3.356µ ±  1%
JQTransform_Complex-4                    40.58µ ±  2%
JQTransform_Throughput-4                 1.691µ ±  0%
SSEPublishDelivery-4                     56.77n ±  1%
geomean                                  1.572µ

                                 │ baseline-bench.txt │
                                 │        B/op        │
JQTransform_Simple-4                   1.273Ki ± 0%
JQTransform_ObjectConstruction-4       1.773Ki ± 0%
JQTransform_ArraySelect-4              2.625Ki ± 0%
JQTransform_Complex-4                  16.22Ki ± 0%
JQTransform_Throughput-4               1.984Ki ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │
                                 │     allocs/op      │
JQTransform_Simple-4                     10.00 ± 0%
JQTransform_ObjectConstruction-4         15.00 ± 0%
JQTransform_ArraySelect-4                30.00 ± 0%
JQTransform_Complex-4                    324.0 ± 0%
JQTransform_Throughput-4                 17.00 ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                       1.126µ ± 7%
SchemaValidation_AllFields-4                    1.682µ ± 6%
SchemaValidation_FormatValidation-4             1.608µ ± 1%
SchemaValidation_ManySchemas-4                  1.834µ ± 3%
geomean                                         1.537µ

                                    │ benchmark-results.txt │
                                    │         B/op          │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

                                    │ benchmark-results.txt │
                                    │       allocs/op       │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

cpu: AMD EPYC 9V74 80-Core Processor                
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                    1.088µ ± 2%
SchemaValidation_AllFields-4                 1.619µ ± 2%
SchemaValidation_FormatValidation-4          1.581µ ± 2%
SchemaValidation_ManySchemas-4               1.582µ ± 2%
geomean                                      1.448µ

                                    │ baseline-bench.txt │
                                    │        B/op        │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │
                                    │     allocs/op      │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   1.370µ ± 22%
EventStoreAppend_SQLite-4                     1.609m ±  6%
GetTimeline_InMemory/events-10-4              14.00µ ±  3%
GetTimeline_InMemory/events-50-4              78.15µ ± 21%
GetTimeline_InMemory/events-100-4             124.5µ ±  1%
GetTimeline_InMemory/events-500-4             643.1µ ±  1%
GetTimeline_InMemory/events-1000-4            1.304m ±  1%
GetTimeline_SQLite/events-10-4                108.8µ ±  1%
GetTimeline_SQLite/events-50-4                249.5µ ±  1%
GetTimeline_SQLite/events-100-4               422.1µ ±  0%
GetTimeline_SQLite/events-500-4               1.788m ±  0%
GetTimeline_SQLite/events-1000-4              3.491m ±  1%
geomean                                       226.3µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                     764.0 ± 4%
EventStoreAppend_SQLite-4                     1.985Ki ± 3%
GetTimeline_InMemory/events-10-4              7.953Ki ± 0%
GetTimeline_InMemory/events-50-4              46.62Ki ± 0%
GetTimeline_InMemory/events-100-4             94.48Ki ± 0%
GetTimeline_InMemory/events-500-4             472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4            944.3Ki ± 0%
GetTimeline_SQLite/events-10-4                16.74Ki ± 0%
GetTimeline_SQLite/events-50-4                87.14Ki ± 0%
GetTimeline_SQLite/events-100-4               175.4Ki ± 0%
GetTimeline_SQLite/events-500-4               846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4              1.639Mi ± 0%
geomean                                       67.16Ki

                                   │ benchmark-results.txt │
                                   │       allocs/op       │
EventStoreAppend_InMemory-4                     7.000 ± 0%
EventStoreAppend_SQLite-4                       53.00 ± 0%
GetTimeline_InMemory/events-10-4                125.0 ± 0%
GetTimeline_InMemory/events-50-4                653.0 ± 0%
GetTimeline_InMemory/events-100-4              1.306k ± 0%
GetTimeline_InMemory/events-500-4              6.514k ± 0%
GetTimeline_InMemory/events-1000-4             13.02k ± 0%
GetTimeline_SQLite/events-10-4                  382.0 ± 0%
GetTimeline_SQLite/events-50-4                 1.852k ± 0%
GetTimeline_SQLite/events-100-4                3.681k ± 0%
GetTimeline_SQLite/events-500-4                18.54k ± 0%
GetTimeline_SQLite/events-1000-4               37.29k ± 0%
geomean                                        1.162k

cpu: AMD EPYC 9V74 80-Core Processor                
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.142µ ± 18%
EventStoreAppend_SQLite-4                  1.064m ±  3%
GetTimeline_InMemory/events-10-4           12.71µ ±  3%
GetTimeline_InMemory/events-50-4           54.76µ ± 12%
GetTimeline_InMemory/events-100-4          109.8µ ±  2%
GetTimeline_InMemory/events-500-4          564.1µ ±  0%
GetTimeline_InMemory/events-1000-4         1.149m ±  0%
GetTimeline_SQLite/events-10-4             90.10µ ±  1%
GetTimeline_SQLite/events-50-4             226.2µ ±  0%
GetTimeline_SQLite/events-100-4            390.2µ ±  0%
GetTimeline_SQLite/events-500-4            1.677m ±  0%
GetTimeline_SQLite/events-1000-4           3.268m ±  5%
geomean                                    192.7µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  798.0 ± 8%
EventStoreAppend_SQLite-4                  1.982Ki ± 2%
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%
geomean                                    67.40Ki

                                   │ baseline-bench.txt │
                                   │     allocs/op      │
EventStoreAppend_InMemory-4                  7.000 ± 0%
EventStoreAppend_SQLite-4                    53.00 ± 0%
GetTimeline_InMemory/events-10-4             125.0 ± 0%
GetTimeline_InMemory/events-50-4             653.0 ± 0%
GetTimeline_InMemory/events-100-4           1.306k ± 0%
GetTimeline_InMemory/events-500-4           6.514k ± 0%
GetTimeline_InMemory/events-1000-4          13.02k ± 0%
GetTimeline_SQLite/events-10-4               382.0 ± 0%
GetTimeline_SQLite/events-50-4              1.852k ± 0%
GetTimeline_SQLite/events-100-4             3.681k ± 0%
GetTimeline_SQLite/events-500-4             18.54k ± 0%
GetTimeline_SQLite/events-1000-4            37.29k ± 0%
geomean                                     1.162k

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

@intel352
Copy link
Contributor

@copilot apply changes based on the comments in this thread

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 14, 2026

@copilot apply changes based on the comments in this thread

Fixed in d34fb69: os.Pipe() error is now checked with t.Fatalf, the read end r is closed via t.Cleanup, and os.Stderr is also restored via t.Cleanup so it's reliably reset even on early test failures.

@intel352 intel352 merged commit f47b71c into main Mar 14, 2026
15 checks passed
@intel352 intel352 deleted the copilot/fix-wfctl-version-check branch March 14, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants